Skip to content

[libclang/python] Add type annotations for code completion classes #140539

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

DeinAlptraum
Copy link
Contributor

This fully annotates the code completion classes (CompletionChunk, CompletionString, CodeCompletionResult, CodeCompletionResults and CCRStructure) resolving 59 strict typing errors as the next step towards #76664

@DeinAlptraum DeinAlptraum requested a review from Endilll May 19, 2025 13:23
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:as-a-library libclang and C++ API labels May 19, 2025
@llvmbot
Copy link
Member

llvmbot commented May 19, 2025

@llvm/pr-subscribers-clang

Author: Jannick Kremer (DeinAlptraum)

Changes

This fully annotates the code completion classes (CompletionChunk, CompletionString, CodeCompletionResult, CodeCompletionResults and CCRStructure) resolving 59 strict typing errors as the next step towards #76664


Full diff: https://github.com/llvm/llvm-project/pull/140539.diff

1 Files Affected:

  • (modified) clang/bindings/python/clang/cindex.py (+38-31)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index f65bcad780a70..1dadd44f7d564 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -110,6 +110,7 @@
         "tuple[str, Optional[list[Any]], Any]",
         "tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
     ]
+    CObjP: TypeAlias = _Pointer[Any]
 
     TSeq = TypeVar("TSeq", covariant=True)
 
@@ -2960,25 +2961,26 @@ class _CXUnsavedFile(Structure):
 
 class CompletionChunk:
     class Kind:
-        def __init__(self, name):
+
+        def __init__(self, name: str):
             self.name = name
 
-        def __str__(self):
+        def __str__(self) -> str:
             return self.name
 
-        def __repr__(self):
+        def __repr__(self) -> str:
             return "<ChunkKind: %s>" % self
 
-    def __init__(self, completionString, key):
+    def __init__(self, completionString: CObjP, key: int):
         self.cs = completionString
         self.key = key
         self.__kindNumberCache = -1
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return "{'" + self.spelling + "', " + str(self.kind) + "}"
 
     @CachedProperty
-    def spelling(self):
+    def spelling(self) -> str:
         if self.__kindNumber in SPELLING_CACHE:
             return SPELLING_CACHE[self.__kindNumber]
         return _CXString.from_result(
@@ -2989,7 +2991,7 @@ def spelling(self):
     # apparently still significantly faster. Please profile carefully if you
     # would like to add CachedProperty back.
     @property
-    def __kindNumber(self):
+    def __kindNumber(self) -> int:
         if self.__kindNumberCache == -1:
             self.__kindNumberCache = conf.lib.clang_getCompletionChunkKind(
                 self.cs, self.key
@@ -2997,30 +2999,30 @@ def __kindNumber(self):
         return self.__kindNumberCache
 
     @CachedProperty
-    def kind(self):
+    def kind(self) -> Kind:
         return completionChunkKindMap[self.__kindNumber]
 
     @CachedProperty
-    def string(self):
+    def string(self) -> CompletionString | None:
         res = conf.lib.clang_getCompletionChunkCompletionString(self.cs, self.key)
 
         if not res:
             return None
         return CompletionString(res)
 
-    def isKindOptional(self):
+    def isKindOptional(self) -> bool:
         return self.__kindNumber == 0
 
-    def isKindTypedText(self):
+    def isKindTypedText(self) -> bool:
         return self.__kindNumber == 1
 
-    def isKindPlaceHolder(self):
+    def isKindPlaceHolder(self) -> bool:
         return self.__kindNumber == 3
 
-    def isKindInformative(self):
+    def isKindInformative(self) -> bool:
         return self.__kindNumber == 4
 
-    def isKindResultType(self):
+    def isKindResultType(self) -> bool:
         return self.__kindNumber == 15
 
 
@@ -3051,6 +3053,7 @@ def isKindResultType(self):
 
 class CompletionString(ClangObject):
     class Availability:
+
         def __init__(self, name):
             self.name = name
 
@@ -3060,14 +3063,14 @@ def __str__(self):
         def __repr__(self):
             return "<Availability: %s>" % self
 
-    def __len__(self):
+    def __len__(self) -> int:
         return self.num_chunks
 
     @CachedProperty
-    def num_chunks(self):
+    def num_chunks(self) -> int:
         return conf.lib.clang_getNumCompletionChunks(self.obj)  # type: ignore [no-any-return]
 
-    def __getitem__(self, key):
+    def __getitem__(self, key: int) -> CompletionChunk:
         if self.num_chunks <= key:
             raise IndexError
         return CompletionChunk(self.obj, key)
@@ -3075,24 +3078,24 @@ def __getitem__(self, key):
     if TYPE_CHECKING:
         # Defining __getitem__ and __len__ is enough to make an iterable
         # but the typechecker doesn't understand that.
-        def __iter__(self):
+        def __iter__(self) -> Iterator[CompletionChunk]:
             for i in range(len(self)):
                 yield self[i]
 
     @property
-    def priority(self):
+    def priority(self) -> int:
         return conf.lib.clang_getCompletionPriority(self.obj)  # type: ignore [no-any-return]
 
     @property
-    def availability(self):
+    def availability(self) -> CompletionChunk.Kind:
         res = conf.lib.clang_getCompletionAvailability(self.obj)
         return availabilityKinds[res]
 
     @property
-    def briefComment(self):
+    def briefComment(self) -> str:
         return _CXString.from_result(conf.lib.clang_getCompletionBriefComment(self.obj))
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return (
             " | ".join([str(a) for a in self])
             + " || Priority: "
@@ -3115,25 +3118,28 @@ def __repr__(self):
 class CodeCompletionResult(Structure):
     _fields_ = [("cursorKind", c_int), ("completionString", c_object_p)]
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return str(CompletionString(self.completionString))
 
     @property
-    def kind(self):
+    def kind(self) -> CursorKind:
         return CursorKind.from_id(self.cursorKind)
 
     @property
-    def string(self):
+    def string(self) -> CompletionString:
         return CompletionString(self.completionString)
 
 
 class CCRStructure(Structure):
     _fields_ = [("results", POINTER(CodeCompletionResult)), ("numResults", c_int)]
 
-    def __len__(self):
+    results: NoSliceSequence[CodeCompletionResult]
+    numResults: int
+
+    def __len__(self) -> int:
         return self.numResults
 
-    def __getitem__(self, key):
+    def __getitem__(self, key: int) -> CodeCompletionResult:
         if len(self) <= key:
             raise IndexError
 
@@ -3141,18 +3147,19 @@ def __getitem__(self, key):
 
 
 class CodeCompletionResults(ClangObject):
-    def __init__(self, ptr):
+
+    def __init__(self, ptr: _Pointer[CCRStructure]):
         assert isinstance(ptr, POINTER(CCRStructure)) and ptr
         self.ptr = self._as_parameter_ = ptr
 
-    def from_param(self):
+    def from_param(self) -> _Pointer[CCRStructure]:
         return self._as_parameter_
 
-    def __del__(self):
+    def __del__(self) -> None:
         conf.lib.clang_disposeCodeCompleteResults(self)
 
     @property
-    def results(self):
+    def results(self) -> CCRStructure:
         return self.ptr.contents
 
     @property

Copy link

github-actions bot commented May 19, 2025

✅ With the latest revision this PR passed the Python code formatter.

@@ -3051,6 +3053,7 @@ def isKindResultType(self):

class CompletionString(ClangObject):
class Availability:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not annotate this class because it isn't used. I assume the availability property accessing availabilityKinds was supposed to use that, but availabilityKinds uses the CompletionChunk.Kind class:

availabilityKinds = {
0: CompletionChunk.Kind("Available"),
1: CompletionChunk.Kind("Deprecated"),
2: CompletionChunk.Kind("NotAvailable"),
3: CompletionChunk.Kind("NotAccessible"),
}

So either the CompletionString.Availability class should be removed, or actually used for that. This would be a breaking change technically (if anyone checks the type of the returned kind object or its repr) but otherwise these two classes have the same interface anyway.

Could also be changed to either some common class or use Python's builtin Enum class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:as-a-library libclang and C++ API clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants